#include "RenderTarget.h"

namespace Nezha
{
	DepthStencilBuffer::DepthStencilBuffer(u8 bitDepth, u16 w, u16 h)
		:mBitDepth(bitDepth)
		,mWidth(w)
		,mHeight(h)
		,mHandle(0)
	{
	}

	bool DepthStencilBuffer::isCompatible(RenderTarget* rt) const
	{
		// AA?
		if(mWidth >= rt->getWidth() && mHeight >= rt->getHeight())
		{
			return true;
		}

		return false;
	}


	RenderTarget::RenderTarget()
		:mPriority(0)
		,mColorDepth(32)
		,mWidth(640)
		,mHeight(480)
		,mVisiblityMask(NEZHA_CULLING_MASK_ALL)
	{

	}

	RenderTarget::~RenderTarget()
	{
		mDepthStencilBuffer = NULL;

		removeAllViewports();
	}

	void RenderTarget::setCamera(Camera* cam)
	{
		mCamera = cam;
	}

	void RenderTarget::addListener(RenderTargetListener* rtl)
	{
		if(rtl)
		{
			mListeners.push_back(rtl);
		}
	}

	void RenderTarget::removeListener(RenderTargetListener* rtl)
	{
		RTListenerList::iterator it = find(mListeners.begin(), mListeners.end(), rtl);
		if(it != mListeners.end())
		{
			mListeners.erase(it);
		}
	}

	void RenderTarget::removeAllListeners()
	{
		mListeners.clear();
	}

	bool RenderTarget::attachDepthStencilBuffer(DepthStencilBuffer* ds)
	{
		if(ds)
		{
			if(ds->getBitDepth() != getColorDepth() || ds->getWidth() != getWidth()
				|| ds->getHeight() != getHeight())
			{
				return false;
			}

			if(mDepthStencilBuffer != ds)
				detachDepthStencilBuffer();

			mDepthStencilBuffer = ds;

			return true;
		}

		return false;
	}

	void RenderTarget::detachDepthStencilBuffer()
	{
		mDepthStencilBuffer = NULL;
	}

	void RenderTarget::setVisiblityMask(u32 msk)
	{
		mVisiblityMask = msk;
	}

	Viewport* RenderTarget::addViewport(int priority, const RectI& subRect)
	{
		// can't be too much viewports be added, so lower_bound is not needed.
		for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
		{
			if((*it)->getPriority() == priority)
			{
				return NULL;
			}
		}

		Viewport* vp = NZ_New Viewport();
		vp->setViewportRect(subRect);
		vp->mPriority = priority;

		for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
		{
			if((*it)->getPriority() <= priority)
			{
				mViewportList.insert(it, vp);
				return vp;
			}
		}

		mViewportList.push_back(vp);

		return vp;
	}

	Viewport* RenderTarget::getViewport(u32 i)
	{
		if(i < mViewportList.size())
		{
			return mViewportList[i];
		}

		return NULL;
	}

	void RenderTarget::removeViewport(int priority)
	{
		for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
		{
			if((*it)->getPriority() == priority)
			{
				NZ_Delete (*it);
				mViewportList.erase(it);
				return;
			}
		}
	}

	void RenderTarget::removeAllViewports()
	{
		for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
		{
			NZ_Delete (*it);
		}

		mViewportList.clear();
	}

	void RenderTarget::resetViewportPriority(Viewport* vp, int priority)
	{
		if(vp)
		{
			for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
			{
				if((*it) == vp)
				{
					mViewportList.erase(it);
					break;
				}
			}

			vp->mPriority = priority;

			for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
			{
				if((*it)->getPriority() <= priority)
				{
					mViewportList.insert(it, vp);
					return;
				}
			}
		}
	}

	Viewport* RenderTarget::getViewportPriority(int priority)
	{
		for(ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); it++)
		{
			if((*it)->getPriority() == priority)
			{
				return (*it);
			}
		}

		return NULL;
	}

	void RenderTarget::preDraw(Viewport* vp)
	{
		for(RTListenerList::iterator it = mListeners.begin(); it != mListeners.end(); it++)
		{
			(*it)->onPreDraw(vp);
		}

		_preDraw(vp);
	}

	void RenderTarget::postDraw(Viewport* vp)
	{
		for(RTListenerList::iterator it = mListeners.begin(); it != mListeners.end(); it++)
		{
			(*it)->onPostDraw(vp);
		}

		_postDraw(vp);
	}

}//end namespace Nezha